//main process loop
// Created: Daly 2012-04-20
//

#include "ax_common.h"
#include "global.h"
#include "config.h"
#include <xnt_event.h>
#include <xnt_timer.h>

static int _process_init = 0;
AxConnection *g_netd_conn = NULL;
static int _netd_connected = 0;
static int _netd_reconn = 0;

void init_net()
{
	xnt_conf_t cf;
	if (_process_init != 0) return;

	cf.timetick = 1000 / GConf::fps;
	cf.max_fd = 10;
	if (xnt_init(&cf) != 0) {
		engine_abort("event driver failed");
		return;
	}
	
	_process_init = 1;
}

void on_recv_netd(xnt_event_t *ev, int fd)
{
	int ret;
	AxConnection *c;
	if (g_netd_conn == NULL) return;	
	c = g_netd_conn;
	ret = c->read();
	if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
		return;  //no data, try next time
	}
	
}

void on_send_netd(xnt_event_t *ev, int fd)
{
	int error = 0;
	socklen_t len;
	AxConnection *c;
	if (g_netd_conn == NULL) return;
	c = g_netd_conn;
	if (!_netd_connected) {	
		if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len) < 0)
		{
			debug_msg("fail to connect netd. port=%d", GConf::netd_port);
			c->close();
			return;
		}
		if (error) {
			//berkeley socket will return 0 but errno not zero when error 
			debug_msg("fail to connect netd. port=%d errno=%d", GConf::netd_port, error);
			c->close();
			return;
		}
		//connect
		_netd_connected = 1;  //connect ok
		g_netd_conn = 0;
		xnt_del_event(&c->wev, c->fd, XNT_EV_WRITE);
		debug_msg("connected to NETD");
		return;
	}
}

void connect_netd()
{
	int connect_ret;
	struct sockaddr_in addr;
	
	init_net();
	if (g_netd_conn != NULL) {
		g_netd_conn->close();
		_netd_connected = 0;	
	} else {
		g_netd_conn = new AxConnection(100000, 1000);
	}

	g_netd_conn->fd = ::socket(AF_INET, SOCK_STREAM, 0);
	ax_set_nonblock(g_netd_conn->fd);
	bzero(&addr, sizeof(addr));
	addr.sin_family=AF_INET;
	addr.sin_port=htons(GConf::netd_port);
	inet_aton("127.0.0.1", &addr.sin_addr);  //local netd
	connect_ret = ::connect(g_netd_conn->fd, (struct sockaddr *)&addr, sizeof(addr));	

	printf("here ret:%d errno:%d \n", connect_ret, errno);
	if(connect_ret == -1 
		&& errno != EINPROGRESS && errno != EAGAIN && errno != EALREADY)
	{
		if (errno == EISCONN) return;
		debug_msg("fail to connect NETD. port:%d", GConf::netd_port);	
		g_netd_conn->close();
		_netd_connected = 0;
		return;
	} 
	if (connect_ret == 0) {
		//ok immediately (seldom occur)
		g_netd_conn->rev.handler = on_recv_netd;
		g_netd_conn->rev.data = (void*)g_netd_conn->fd;
		xnt_add_event(&g_netd_conn->rev, g_netd_conn->fd, XNT_EV_READ);		
		_netd_connected = 1;
		_netd_reconn = 0;
		debug_msg("connected to NETD");
	} else {
		//connect in progress
		g_netd_conn->wev.handler = on_send_netd;
		g_netd_conn->wev.data = (void*)g_netd_conn->fd;
		xnt_add_event(&g_netd_conn->wev, g_netd_conn->fd, XNT_EV_WRITE);
	}
}

void check_connect(int handle)
{
	xnt_add_timer(check_connect, 5000);
	if (!_netd_connected) {
		if (_netd_reconn > MAX_CONNECT_TRY) {
			engine_abort("cannot connect to netd");
			return;
		}
		connect_netd();	
		_netd_reconn++;
	}
}

void process_timer(int handle)
{
	xnt_add_timer(process_timer, 1000);
}

void dispatch()
{
	xnt_add_timer(check_connect, 5000);
	xnt_add_timer(process_timer, 1000);
	while(1) {
        xnt_process();
	}
}

